package main

import (
	"fmt"
	"math"
	"strings"
	"time"
    "os"
    "encoding/hex"
    "reflect"
    "strconv"
    "encoding/json"
    "encoding/xml"
)

func main() {
	fmt.Printf("Hello, 世界\n")
	a, b := swap("hello", "world")
	fmt.Println(a, b)

	//stringers
	//Reference http://research.swtch.com/gotour
	fmt.Printf("Hello, %s\n", new(Golang))
	fmt.Printf("%s！\n", Beijing)                       //欢迎来北京！
	fmt.Printf("Today is: %s\n", time.Now().Weekday()) //Weekday: Monday
    //print hex using encoding.hex.Dumper, io.Writer
    h := hex.Dumper(os.Stdout)
    defer h.Close()
    fmt.Fprintln(h, Shanghai)
    //Refletion
    var myPrint = func (args ...interface{}) {
        for _, arg := range args {
            switch v := reflect.ValueOf(arg); v.Kind() {
            case reflect.String:
                os.Stdout.WriteString(v.String())
            case reflect.Int:
                os.Stdout.WriteString(strconv.FormatInt(v.Int(),10))
            }
        }
    }
    myPrint("Hello ", 100, "\n")

    //print struct
    golang := Lang{"Go", 2009, "http://golang.org"}
    fmt.Printf("%v\n", golang)
    fmt.Printf("%+v\n", golang)
    fmt.Printf("%#v\n", golang)
    //struct to JSON
    jsonData, _ := json.Marshal(golang)// or MarshalIndent
    fmt.Println(string(jsonData))
    //struct to XML
    xmlData, _ := xml.MarshalIndent(golang, "", " ")
    fmt.Println(string(xmlData))

    start := time.Now()
	fmt.Println(sqrt(2))
    fmt.Printf("%.2fs total\n", time.Since(start).Seconds())
	fmt.Println(math.Sqrt(2))

	//array Slice Map Set
	//Reference http://se77en.cc/2014/06/30/array-slice-map-and-set-in-golang/
	var ar1 [3]int
	ar2 := [...]int{3, 5, 8}
	ar1 = ar2
	ar1[2] = 100
	fmt.Printf("%v\n", ar2) //[3 5 8]
	langs := [...]string{"go", "c", "python"}
	fmt.Printf("%v\n", langs) //[go c python]
	//Slice
	slice1 := make([]string, 5)
	slice2 := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
	slice1 = slice2[1:3] //length = 2
	slice1[1] = "Black"
	slice1 = append(slice1, "White")
	fmt.Printf("%v\n", slice1) //[Blue Black White]
	for index, value := range slice2 {
		fmt.Printf("Index: %d,Value: %s;\n", index, value)
	} //Index: 0,Value: Red;Index: 1,Value: Blue;...
	//Map
	colors := map[string]string{"Orange": "#e95a22"}
	colors["Red"] = "#da1337"
	fmt.Printf("%v\n", colors) //map[Red:#da1337 Orange:#e95a22]
	fmt.Printf("%v\n", WordCount("name   hello world name"))

	//use interface
	r := Rectangle{length: 5, width: 3}
	s := Shaper(r)
	fmt.Println("Area of the Shape r is: ", s.Area())

	//closure
	f := Fibonacci()
	fmt.Printf("Fibonacci(closure): ")
	for i := 0; i < 10; i++ {
		fmt.Printf("%d,", f())
	}
	fmt.Printf("\n")

	//channel
	fmt.Printf("Fibonacci(channel): ")
	c := make(chan int, 10)
	go Fibonacci_chan(cap(c), c)
	for i := range c {
		fmt.Printf("%d,", i)
	}
	fmt.Printf("\n")
}

func swap(x, y string) (string, string) {
	return y, x
}

func sqrt(x float64) float64 {
	z := float64(1)
	for {
		z = z - (z*z-x)/2*z
		if math.Abs(z*z-x) < 1e-4 {
			return z
		}
	}
	return 0
}

//Stringer
type Golang struct{}

func (g *Golang) String() string {
	return "Go 语言"
}

type Place int

var Addr = [...]string{"北京", "上海"}

const (
	Beijing Place = iota
	Shanghai
)

func (a Place) String() string {
	return "欢迎来" + Addr[a]
}

//Shaper is an interface
type Shaper interface {
	Area() int
}

type Rectangle struct {
	length, width int
}

//Rectangle implements the interface Shaper
//because it has the same function signature Area
func (r Rectangle) Area() int {
	return r.length * r.width
}

//count number of words
func WordCount(s string) map[string]int {
	arr := strings.Fields(s)
	res := map[string]int{}
	for _, v := range arr {
		if res[v] != 0 {
			res[v]++
		} else {
			res[v] = 1
		}
	}
	return res
}

//go closure
func Fibonacci() func() int {
	pre, cur := 1, 0
	return func() int {
		pre, cur = cur, cur+pre
		return cur
	}
}

//go channel
func Fibonacci_chan(n int, c chan int) {
	x, y := 1, 0
	for i := 0; i < n; i++ {
		x, y = y, x+y
		c <- y
	}
	close(c)
}

//A stream
type MyReader struct{}

func (m MyReader) Read(b []byte) (n int, err error) {
	for i, _ := range b {
		b[i] = 'A'
	}
	return len(b), nil
}

//reflect struct
type Lang struct {
    Name string
    Year int
    URL string
}